/*
 * CustomizedLayout
 *
 * This layout manager is customized designed for rendering and managing child Component of forms.
 * It responsible for rendering the label Field, mandatory Field, icon before Field, unit after Field and information bellow Field.
 * This layout manager is used when a Container is configured width the layout: 'customizedlayout'.
 *
 * In ThienTan project, this layout always must be used together with PluginDemo to have customized function for each Field.
 *
 * Each component in layout can accept the following layout-specific configuring properties :
 *      * icon : {String} Value can be hint/lock/disable/error/warning.
 *      * mandatory : {Boolean} {optional} Check whether display default character '*' after Field's Label
 *      * unit : {String} Value for Field's unit.
 */

Ext.Container.prototype.alignIcon = function () {
	if (this.errorIcon) {
		this.errorIcon.alignTo(this.el, 'tl', [-18, 2]);
	}
};

Ext.form.Field.prototype.alignIcon = function () {
	if (this.errorIcon) {
		this.errorIcon.alignTo(this.el, 'tl', [-18, 2]);
		this.errorEl.setWidth(this.getErrorCt().getWidth(true) - 20);
	}
	if (this.unitEl) {
		this.unitEl.alignTo(this.el, 'tr', [2, 0]);
	}
};

CustomizedLayout = Ext.extend(Ext.layout.FormLayout, {

    /**
     * @cfg {String} mandatoryLabel
     * Default character will be display after Field's Label when it has mandatory = true.
     */
    mandatoryLabel : '*',

    /**
     * @private
     * Distance between field and unit label
     */
    unitDistance : 0,

    /**
     * @private
     * Distance between field and icon
     */
    iconDistance : 2,


    /**
     * @override from Ext.layout.FormLayout
     *
     * <p>Provides template arguments for rendering the fully wrapped, labeled, icon, info labeled, unit labeled and styled form Field.</p>
     * <p>This method returns an object hash containing properties used by the layout's {@link #fieldTpl}
     * to create a correctly wrapped, labeled and styled form Field. This may be overriden to
     * create custom layouts. The properties which must be returned are:</p><div class="mdetail-params"><ul>
     * <li><b><tt>itemCls</tt></b> : String<div class="sub-desc">The CSS class applied to the outermost div wrapper
     * that contains this field label and field element (the default class is <tt>'x-form-item'</tt> and <tt>itemCls</tt>
     * will be added to that). If supplied, <tt>itemCls</tt> at the field level will override the default <tt>itemCls</tt>
     * supplied at the container level.</div></li>
     * <li><b><tt>id</tt></b> : String<div class="sub-desc">The id of the Field</div></li>
     * <li><b><tt>{@link #labelStyle}</tt></b> : String<div class="sub-desc">
     * A CSS style specification string to add to the field label for this field (defaults to <tt>''</tt> or the
     * {@link #labelStyle layout's value for <tt>labelStyle</tt>}).</div></li>
     * <li><b><tt>label</tt></b> : String<div class="sub-desc">The text to display as the label for this
     * field (defaults to the field's configured fieldLabel property)</div></li>
     * <li><b><tt>{@link #labelSeparator}</tt></b> : String<div class="sub-desc">The separator to display after
     * the text of the label for this field (defaults to a colon <tt>':'</tt> or the
     * {@link #labelSeparator layout's value for labelSeparator}). To hide the separator use empty string ''.</div></li>
     * <li><b><tt>elementStyle</tt></b> : String<div class="sub-desc">The styles text for the input element's wrapper.</div></li>
     * <li><b><tt>clearCls</tt></b> : String<div class="sub-desc">The CSS class to apply to the special clearing div
     * rendered directly after each form field wrapper (defaults to <tt>'x-form-clear-left'</tt>)</div></li>
     * </ul></div>
     * @param (Ext.form.Field} field The {@link Ext.form.Field Field} being rendered.
     * @return {Object} An object hash containing the properties required to render the Field.
     */
    getTemplateArgs: function(field) {
        var noLabelSep = !field.fieldLabel || field.hideLabel;

        return {
            id : field.id,
            label : field.fieldLabel,
            itemCls : (field.itemCls || this.container.itemCls || '') + (field.hideLabel ? ' x-hide-label' : ''),
            clearCls : field.clearCls || 'x-form-clear-left',
            labelStyle : this.getLabelStyle(field.labelStyle),
            elementStyle : this.elementStyle || '',
            mandatory : field.mandatory ? this.mandatoryLabel : ''
        };
    },


    /**
     * @override from Ext.layout.ContainerLayout
     *
     * The {@link Ext.Template Ext.Template} used by Field rendering layout classes (such as
     * {@link CustomizedLayout}) to create the DOM structure of a fully wrapped, labeled, icon, info labeled, unit labeled and styled from Field.
     * The template processes values returned from {@link CustomizedLayout#getTemplateArgs}.
     * @property fieldTpl
     * @type Ext.Template
     */
    fieldTpl: (function() {
        var t = new Ext.Template(
            '<div class="x-form-item {itemCls}" tabIndex="-1">',
                '<label for="{id}" style="{labelStyle}" class="x-form-item-label">{label}{mandatory}</label>',
                '<div class="x-form-element" id="x-form-el-{id}" style="{elementStyle}">',
                '</div><div class="{clearCls}"></div>',
            '</div>'
        );
        t.disableFormats = true;
        return t.compile();
    })(),

    /**
     * @override from Ext.form.FormLayout
     */
    setContainer : function(ct){
        Ext.layout.FormLayout.superclass.setContainer.call(this, ct);
        if(ct.labelAlign){
            ct.addClass('x-form-label-'+ct.labelAlign);
        }

        if(ct.hideLabels){
            Ext.apply(this, {
                labelStyle: 'display:none',
                elementStyle: 'padding-left:0;',
                labelAdjust: 0
            });
        }else{
            this.labelSeparator = Ext.isDefined(ct.labelSeparator) ? ct.labelSeparator : this.labelSeparator;
            ct.labelWidth = ct.labelWidth || 70;
            if(Ext.isNumber(ct.labelWidth)){
                var pad = Ext.isNumber(ct.labelPad) ? ct.labelPad : 5;
                Ext.apply(this, {
                    labelAdjust: (ct.labelWidth + 18) + pad,
                    labelStyle: 'width:' + (ct.labelWidth + 18) + 'px;',
                    elementStyle: 'padding-left:' + (ct.labelWidth + 18 + pad) + 'px'
                });
            }
            if(ct.labelAlign == 'top'){
                Ext.apply(this, {
                    labelStyle: 'width:auto;',
                    labelAdjust: 0,
                    elementStyle: 'padding-left:0;'
                });
            }
        }
    },

    /**
     * @override from Ext.form.FormLayout
     */
    renderItem : function(c, position, target){
        if(c && (c.isFormField || c.fieldLabel) && c.inputType != 'hidden'){
            var args = this.getTemplateArgs(c);
            if(Ext.isNumber(position)){
                position = target.dom.childNodes[position] || null;
            }
            if(position){
                c.itemCt = this.fieldTpl.insertBefore(position, args, true);
            }else{
                c.itemCt = this.fieldTpl.append(target, args, true);
            }
            if(!c.getItemCt){
                // Non form fields don't have getItemCt, apply it here
                // This will get cleaned up in onRemove
                Ext.apply(c, {
                    getItemCt: function(){
                        return c.itemCt;
                    },
                    customItemCt: true
                });
            }
            c.label = c.getItemCt().child('label.x-form-item-label');
            if(!c.rendered){
                c.render('x-form-el-' + c.id);
            }else if(!this.isValidParent(c, target)){
                Ext.fly('x-form-el-' + c.id).appendChild(c.getPositionEl());
            }
            if(this.trackLabels){
                if(c.hidden){
                    this.onFieldHide(c);
                }
                c.on({
                    scope: this,
                    show: this.onFieldShow,
                    hide: this.onFieldHide
                });
            }
            this.configureItem(c);

            var parent = c.container;
            if (!this.container.hideIcons) {
	            //start customize : create icon, error and unit node
	            c.icon = c.icon ? c.icon : 'edit';

	            // create icon node
	        	if(!c.errorIcon){
	            	var oxycIconCls = 'customizedlayout-icon-' + c.icon;
	                c.errorIcon = parent.createChild({cls: oxycIconCls});
	                if(c.iconToolTipText) {
	                    c.iconToolTip = new Ext.ToolTip({
	                        target : c.errorIcon,
	                        html : c.iconToolTipText
	                    });
	                }
	                c.errorIcon.show();
	            }
            }

        	// create error node
            if(!c.errorEl){
                c.errorEl = parent.createChild({cls:'customizedlayout-msg'});
            	//update the message bellow field.
            	if (c.errorMessage) {
                	c.errorEl.update(c.errorMessage);
                }
            }

            // create unit node
            if(c.unit) {
            	if (c instanceof Ext.form.DisplayField) {
            		c.unitEl = parent.createChild({cls: 'customizedlayout-unit-dispField', html : c.unit});
				} else {
					c.unitEl = parent.createChild({cls: 'customizedlayout-unit', html : c.unit});
				}
            }


            if (c.ownerCt) {
                c.ownerCt.on('afterlayout', c.alignIcon, c);
                c.ownerCt.on('expand', c.alignIcon, c);
            }
            c.on('resize', c.alignIcon, c);
            c.on('destroy', function(){
                Ext.destroy(this.errorIcon);
                Ext.destroy(this.errorEl);
            }, c);
            //end customize
        }else {
            Ext.layout.FormLayout.superclass.renderItem.apply(this, arguments);
        }
    },

    /**
     * @override from Ext.layout.AnchorLayout
     */
    onLayout : function(container, target) {
        Ext.layout.AnchorLayout.superclass.onLayout.call(this, container, target);

        var size = this.getLayoutTargetSize(),
            containerWidth = size.width,
            containerHeight = size.height,
            overflow = target.getStyle('overflow'),
            components = this.getRenderedItems(container),
            len = components.length,
            boxes = [],
            box,
            anchorWidth,
            anchorHeight,
            component,
            anchorSpec,
            calcWidth,
            calcHeight,
            anchorsArray,
            totalHeight = 0,
            i,
            el;

        if(containerWidth < 20 && containerHeight < 20){
            return;
        }

        // find the container anchoring size
        if(container.anchorSize) {
            if(typeof container.anchorSize == 'number') {
                anchorWidth = container.anchorSize;
            } else {
                anchorWidth = container.anchorSize.width;
                anchorHeight = container.anchorSize.height;
            }
        } else {
            anchorWidth = container.initialConfig.width;
            anchorHeight = container.initialConfig.height;
        }

        for(i = 0; i < len; i++) {
            component = components[i];
            el = component.getPositionEl();

            // If a child container item has no anchor and no specific width, set the child to the default anchor size
            if (!component.anchor && component.items && !Ext.isNumber(component.width) && !(Ext.isIE6 && Ext.isStrict)){
                component.anchor = this.defaultAnchor;
            }

            if(component.anchor) {
                anchorSpec = component.anchorSpec;
                // cache all anchor values
                if(!anchorSpec){
                    anchorsArray = component.anchor.split(' ');
                    component.anchorSpec = anchorSpec = {
                        right: this.parseAnchor(anchorsArray[0], component.initialConfig.width, anchorWidth),
                        bottom: this.parseAnchor(anchorsArray[1], component.initialConfig.height, anchorHeight)
                    };
                }
                calcWidth = anchorSpec.right ? this.adjustWidthAnchor(anchorSpec.right(containerWidth) - el.getMargins('lr'), component) : undefined;
                calcHeight = anchorSpec.bottom ? this.adjustHeightAnchor(anchorSpec.bottom(containerHeight) - el.getMargins('tb'), component) : undefined;


                //start customize :
                if(component.unitEl) {
                    calcWidth = calcWidth - component.unitEl.getWidth() - this.unitDistance;
                }
                //end customize

                if(calcWidth || calcHeight) {
                    boxes.push({
                        component: component,
                        width: calcWidth || undefined,
                        height: calcHeight || undefined
                    });
                }
            }
        }
        for (i = 0, len = boxes.length; i < len; i++) {
            box = boxes[i];
            box.component.setSize(box.width, box.height);
            this.applyComponentState(box.component);
        }

        if (overflow && overflow != 'hidden' && !this.adjustmentPass) {
            var newTargetSize = this.getLayoutTargetSize();
            if (newTargetSize.width != size.width || newTargetSize.height != size.height){
                this.adjustmentPass = true;
                this.onLayout(container, target);
            }
        }

        delete this.adjustmentPass;
    },

    applyComponentState : function(c) {
        switch(c.icon) {
            case 'lock':
                c.setDisabled(true);
                break;
            case 'hidden':
                //TODO : each component must have function to clear its contain.
                if(c instanceof Ext.form.ComboBox){
                    // This function is applied in CustomizedFieldPlugin to each component which is accepted in here
                    c.hideValue();
                } else if(c && (c.isFormField || c.fieldLabel) && c.inputType != 'hidden'){
                    // TODO DTL --> TTA : What'll happen if we submit a hidden field? Value field is reset to empty now
                    c.setDisabled(true);
                    c.setValue('');
                }
                break;
            case 'disable':
                c.setDisabled(true);
                break;
            case 'warning':
                break;
            case 'error':
                break;
            default:
                break;
        }

    }
});

Ext.Container.LAYOUTS['customizedlayout'] = CustomizedLayout;